package org.xteam.box2text.old;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

import org.xteam.box2text.Frame;
import org.xteam.box2text.Point;
import org.xteam.box2text.TextStruct;

public class HVOperator extends Operator implements IPlaceableBox {
	
	public HVOperator(Box...boxes) {
		super(boxes);
	}

	public HVOperator(Map<String, Integer> options, List<Box> boxes) {
		super(options, boxes);
	}

	public int width(Frame frame) {
		return new VOperator(options, arguments).width(frame);
	}
	
	@Override
	public List<Box> normalizeGroups(boolean splice) {
		return Arrays.asList(new Box[] { new HVOperator(options, normalizeChildren(true)) });
	}

	public TextStruct place(Frame frame, TextStruct textStruct, int context) {
		if (isEmpty())
			return textStruct;
		
		if (size() == 1)
			return ((IPlaceableBox)arguments.get(0)).place(frame, textStruct, context);

		//BoxPoint bp = length(frame, OperatorKinds.H);
		int Hs = frame.getHs(options);
		int Vs = frame.getVs(options);
		int Is = frame.getIs(options);
		return hvplace(arguments, //((HVOperator)bp.boxes().get(0)).arguments,
				Hs, Vs, Is, frame.setLeftMargin(frame.x()), textStruct);
	}

	private static TextStruct hvplace(List<Box> boxes, int hs, int vs, int is,
			Frame frame, TextStruct textStruct) {
		boolean isFirst = true;
		for (Box box : boxes) {
			Point bp = ((IPlaceableBox)box).length(frame, OperatorKinds.H);
			if (!bp.isZero()) {
				if (isFirst) {
					isFirst = false;
					textStruct = ((IPlaceableBox)box).place(frame, textStruct, OperatorKinds.H);
				} else {
					Frame f = frame.hsep(textStruct.point(), hs);
					textStruct = reshuffle((IPlaceableBox)box, bp, f, textStruct, hs, vs, is);
				}
			}
		}
		return textStruct;
	}

	private static TextStruct reshuffle(IPlaceableBox box, Point size,
			Frame frame, TextStruct textStruct, int hs, int vs, int is) {
		if (size.y() == 0
				&& (frame.x() + size.x()) <= frame.getRightMargin()) {
			return box.place(frame, textStruct, OperatorKinds.H);
		}
		Frame f = frame.setPoint(frame.getLeftMargin() + is, frame.y() + vs);
        return box.place(f, textStruct, OperatorKinds.V);
	}

	public Point length(Frame frame, int context) {
		if (isEmpty()) {
			return new Point(0,0);
		}
		return hvlength(arguments, frame.getHs(options), frame);
	}
	
	private static Point hvlength(List<Box> arguments, int hs, Frame frame) {
		Point bp = null;
		for (Box arg : arguments) {
			Point bpn = ((IPlaceableBox)arg).length(frame, OperatorKinds.H);
			if (bp == null) {
				bp = bpn;
			} else {
				bp = hv(bp, bpn, hs);
			}
		}
		return bp;
	}
	
	private static Point hv(Point p1, Point p2, int hs) {
		if (p2.isZero())
			return p1;
		if (p2.height() == 0) {
			return new Point(p1.width() + hs + p2.width(), p1.height());
		}
		return new Point(p2.width(), p1.height() + 1 + p2.height());
	}
	
}
